﻿using Engine;
using Engine.Graphics;
using Game;
using GameEntitySystem;
using NekoMeko.Common;
using Neorxna;
using Neorxna.Anim;
using Neorxna.Common;
using Neorxna.Components;
using Neorxna.Graphic;
using Neorxna.NeoModel;
using System;
using System.Collections.Generic;
using System.Linq;
using TemplatesDatabase;
using static Game.Profiler;

namespace NekoMeko.Components
{
	public class ComponentNekoMekoModel : Component, INeoModel, IUpdateable
	{
		public SubsystemNekoPlayerData SubsystemNekoPlayerData
		{
			get; set;
		}
		public ComponentModel TargetComponent
		{
			get; set;
		}
		public ComponentCreature ComponentCreature
		{
			get; private set;
		}
		public ComponentMiner ComponentMiner
		{
			get; private set;
		}
		public ComponentPlayer ComponentPlayer
		{
			get; private set;
		}
		public ComponentFirstPersonModel ComponentFirstPersonModel
		{
			get; private set;
		}
		public ComponentNeoModel ComponentNeoModel
		{
			get; private set;
		}
		public ComponentNekoMekoOuterModel ComponentNekoMekoOuterModel
		{
			get; private set;
		}
		public ComponentLocomotion ComponentLocomotion => ComponentCreature.ComponentLocomotion;
		public ComponentBody ComponentBody => ComponentCreature.ComponentBody;
		public Model Model => TargetComponent?.Model;
		public Model FirstPersonModel => ComponentNeoModel.FirstPersonModel;
		public Texture2D Texture => ComponentNeoModel.TextureOverride;
		public UpdateOrder UpdateOrder => UpdateOrder.Default;
		public bool ShouldOverride(ComponentModel componentModel) => componentModel.GetType() == typeof(ComponentHumanModel);

		public Dictionary<string, Matrix> BoneTransforms
		{
			get; set;
		} = [];

		bool m_initialized;
		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			base.Load(valuesDictionary, idToEntityMap);
			SubsystemNekoPlayerData = Project.FindSubsystem<SubsystemNekoPlayerData>(throwOnError: true);
			TargetComponent = Entity.FindComponent<ComponentHumanModel>(throwOnError: true);
			ComponentCreature = Entity.FindComponent<ComponentCreature>(throwOnError: true);
			ComponentNeoModel = Entity.FindComponent<ComponentNeoModel>(throwOnError: true);
			ComponentMiner = Entity.FindComponent<ComponentMiner>();
			ComponentPlayer = Entity.FindComponent<ComponentPlayer>();
			ComponentFirstPersonModel = Entity.FindComponent<ComponentFirstPersonModel>();
			ComponentNekoMekoOuterModel = Entity.FindComponent<ComponentNekoMekoOuterModel>();
			m_initialized = false;
		}
		public bool SetModel(Model model)
		{
			m_boneTransformsVanilla.Clear();
			bool skip = false;
			if (ResModel != null)
			{
				ComponentNeoModel.BoneSet = ResModel.GetBoneSet();
				ComponentNeoModel.FirstPersonModel = null;
				if ((ResModel.ResPath?.TryGetValue("FirstPersonModelName", out var firstPersonModelName) ?? false) && !string.IsNullOrEmpty(firstPersonModelName))
				{
					ComponentNeoModel.FirstPersonModel = ResModel.GetRes(firstPersonModelName) as Model;
				}
				if ((ResModel.ResPath?.TryGetValue("FirstPersonArms2ModelName", out var firstPersonArms2ModelName) ?? false) && !string.IsNullOrEmpty(firstPersonArms2ModelName))
				{
					ComponentNeoModel.FirstPersonArms2Model = ResModel.GetRes(firstPersonArms2ModelName) as Model;
				}
				if ((ResModel.ResPath?.TryGetValue("ModelName", out var modelName) ?? false) && !string.IsNullOrEmpty(modelName))
				{
					var model1 = ResModel.GetRes(modelName) as Model;
					TargetComponent.m_model = model1;
					if (model1 != null)
					{
						TargetComponent.m_boneTransforms = new Matrix?[model1.Bones.Count];
						TargetComponent.AbsoluteBoneTransformsForCamera = new Matrix[model1.Bones.Count];
						TargetComponent.MeshDrawOrders = [.. Enumerable.Range(0, model1.Meshes.Count)];
						if (TargetComponent is ComponentHumanModel componentHumanModel)
						{
							componentHumanModel.m_bodyBone = model1.FindBone("Body", false);
							componentHumanModel.m_headBone = model1.FindBone("Head", false);
							componentHumanModel.m_leg1Bone = model1.FindBone("Leg1", false);
							componentHumanModel.m_leg2Bone = model1.FindBone("Leg2", false);
							componentHumanModel.m_hand1Bone = model1.FindBone("Arm1", false);
							componentHumanModel.m_hand2Bone = model1.FindBone("Arm2", false);
						}
						ComponentNeoModel.FirstPersonModel ??= NeorxnaUtility.CreateFilteredModel(model1, (name) => name == "Hand2" || name == "Arm2");

						skip = true;
					}
				}
			}
			return skip;
		}
		public bool Animate()
		{
			AnimateCreatureVanilla();
			foreach (var bone in Model.Bones)
			{
				int boneIndex = bone.Index;
				Matrix? transformAnimator = GetBoneTransformAnimator(boneIndex);
				Matrix? transformVanilla = GetBoneTransformVanilla(boneIndex);
				if (transformAnimator.HasValue)
				{
					Matrix matrix = transformAnimator.Value;
					matrix.Translation = new Vector3(matrix.Translation.X, matrix.Translation.Y, -matrix.Translation.Z);
					if (bone == Model.RootBone)
						matrix *= RootTransformVanilla ?? Matrix.Identity;
					else
						matrix = Matrix.CreateRotationX(MathUtils.DegToRad(-90f)) * matrix * Matrix.CreateRotationX(MathUtils.DegToRad(90f));
					SetBoneTransform(boneIndex, matrix);
					//TargetComponent.SetBoneTransform(boneIndex, matrix);
				}
				else if (transformVanilla.HasValue)
					SetBoneTransform(boneIndex, transformVanilla.Value);
				//TargetComponent.SetBoneTransform(boneIndex, transformVanilla);
				else
					SetBoneTransform(boneIndex, Matrix.Identity);
				//TargetComponent.SetBoneTransform(boneIndex, Matrix.Identity);
			}
			return true;
		}
		public bool DrawExtras(Camera camera)
		{
			if (TargetComponent is ComponentHumanModel componentHumanModel && componentHumanModel.m_componentCreature.ComponentHealth.Health > 0f && ComponentMiner != null && ComponentMiner.ActiveBlockValue != 0)
			{
				int num = Terrain.ExtractContents(ComponentMiner.ActiveBlockValue);
				Block block = BlocksManager.Blocks[num];
				foreach (Matrix matrix in ComponentNeoModel.ItemAnchorPositions())
				{
					int x = Terrain.ToCell(matrix.Translation.X);
					int y = Terrain.ToCell(matrix.Translation.Y);
					int z = Terrain.ToCell(matrix.Translation.Z);
					componentHumanModel.m_drawBlockEnvironmentData.DrawBlockMode = DrawBlockMode.ThirdPerson;
					componentHumanModel.m_drawBlockEnvironmentData.InWorldMatrix = matrix;
					componentHumanModel.m_drawBlockEnvironmentData.Humidity = NeorxnaResources.SubsystemTerrain.Terrain.GetSeasonalHumidity(x, z);
					componentHumanModel.m_drawBlockEnvironmentData.Temperature = NeorxnaResources.SubsystemTerrain.Terrain.GetSeasonalTemperature(x, z) + SubsystemWeather.GetTemperatureAdjustmentAtHeight(y);
					componentHumanModel.m_drawBlockEnvironmentData.Light = NeorxnaResources.SubsystemTerrain.Terrain.GetCellLight(x, y, z);
					componentHumanModel.m_drawBlockEnvironmentData.BillboardDirection = -Vector3.UnitZ;
					componentHumanModel.m_drawBlockEnvironmentData.SubsystemTerrain = NeorxnaResources.SubsystemTerrain;
					componentHumanModel.m_drawBlockEnvironmentData.Owner = m_entity;
					Matrix matrix2 = matrix * camera.ViewMatrix;
					block.DrawBlock(NeorxnaResources.SubsystemModelsRenderer.PrimitivesRenderer, ComponentMiner.ActiveBlockValue, Color.White, block.GetInHandScale(ComponentMiner.ActiveBlockValue), ref matrix2, componentHumanModel.m_drawBlockEnvironmentData);
				}
			}
			return true;
		}
		public bool Render(SubsystemModelsRenderer.ModelData modelData, ModelShader modelShader, Camera camera)
		{
			ComponentModel componentModel = modelData.ComponentModel;

			if (ResSkin == null)
				return false;
			Texture2D texture = Texture;
			foreach (var meshIndex in componentModel.MeshDrawOrders)
			{
				var mesh = componentModel.Model.Meshes[meshIndex];
				Matrix world = componentModel.AbsoluteBoneTransformsForCamera[mesh.ParentBone.Index] * camera.InvertedViewMatrix;
				switch (ResSkin.RenderMode)
				{
					case ObjectRenderMode.SolidColor:
					{
						NeorxnaRenderer.DrawSolidColorObject(camera, world, mesh, Color.White);
						break;
					}
					case ObjectRenderMode.Unlit:
					{
						Vector3 v = componentModel.DiffuseColor ?? Vector3.One;
						float num = componentModel.Opacity ?? 1f;
						float ambientLight = NeorxnaRenderer.GetAmbientLight(componentModel.m_componentFrame.Position);
						Vector4 color = new(v * num, num);
						color *= ambientLight * 0.8f;
						NeorxnaRenderer.DrawUnlitObject(camera, world, mesh, texture, new Color(color));
						break;
					}
					case ObjectRenderMode.PBR:
					{
						float ambientLight = NeorxnaRenderer.GetAmbientLight(componentModel.m_componentFrame.Position);
						Texture2D pbrMap = (ResSkin.ResPath?.TryGetValue("PBRMapName", out var pbrMapName) ?? false) && !string.IsNullOrEmpty(pbrMapName)
							? ResSkin.GetRes(pbrMapName) as Texture2D : null;
						Texture2D normalMap = (ResSkin.ResPath?.TryGetValue("NormalMapName", out var normalMapName) ?? false) && !string.IsNullOrEmpty(normalMapName)
							? ResSkin.GetRes(normalMapName) as Texture2D : null;
						NeorxnaRenderer.DrawPBRObject(camera, world, ambientLight, mesh, texture, normalMap, pbrMap, wetness: componentModel.Entity.FindComponent<ComponentVitalStats>()?.Wetness ?? 0f);
						break;
					}
					default:
					{//使用原版ModelShader
						var shader = NeorxnaResources.SubsystemModelsRenderer.m_shaderAlphaTested;
						shader.LightDirection1 = -Vector3.TransformNormal(LightingManager.DirectionToLight1, camera.ViewMatrix);
						shader.LightDirection2 = -Vector3.TransformNormal(LightingManager.DirectionToLight2, camera.ViewMatrix);
						shader.FogColor = new Vector3(NeorxnaResources.SubsystemSky.ViewFogColor);
						shader.FogBottomTopDensity = new Vector3(NeorxnaResources.SubsystemSky.ViewFogBottom - camera.ViewPosition.Y, NeorxnaResources.SubsystemSky.ViewFogTop - camera.ViewPosition.Y, NeorxnaResources.SubsystemSky.ViewFogDensity);
						shader.HazeStartDensity = new Vector2(NeorxnaResources.SubsystemSky.ViewHazeStart, NeorxnaResources.SubsystemSky.ViewHazeDensity);
						shader.FogYMultiplier = NeorxnaResources.SubsystemSky.VisibilityRangeYMultiplier;
						shader.WorldUp = Vector3.TransformNormal(Vector3.UnitY, camera.ViewMatrix);
						shader.Transforms.View = Matrix.Identity;
						shader.Transforms.Projection = camera.ProjectionMatrix;
						shader.SamplerState = SamplerState.PointClamp;
						shader.AlphaThreshold = 0f;
						Vector3 v = componentModel.DiffuseColor ?? Vector3.One;
						float num = componentModel.Opacity ?? 1f;
						shader.InstancesCount = componentModel.AbsoluteBoneTransformsForCamera.Length;
						shader.MaterialColor = new Vector4(v * num, num);
						shader.EmissionColor = componentModel.EmissionColor ?? Vector4.Zero;
						shader.AmbientLightColor = new Vector3(LightingManager.LightAmbient * modelData.Light);
						shader.DiffuseLightColor1 = new Vector3(modelData.Light);
						shader.DiffuseLightColor2 = new Vector3(modelData.Light);
						shader.Texture = texture;
						Array.Copy(componentModel.AbsoluteBoneTransformsForCamera, shader.Transforms.World, componentModel.AbsoluteBoneTransformsForCamera.Length);
						InstancedModelData instancedModelData = InstancedModelsManager.GetInstancedModelData(componentModel.Model, componentModel.MeshDrawOrders);
						Display.DrawIndexed(PrimitiveType.TriangleList, shader, instancedModelData.VertexBuffer, instancedModelData.IndexBuffer, 0, instancedModelData.IndexBuffer.IndicesCount);
						//NeorxnaRenderer.DrawLitObject(camera, world, ambientLight, mesh, texture);
						break;
					}
				}
			}
			return true;
		}

		public void Update(float dt)
		{
			if (!m_initialized)
				Initialize();
			if (NekoMekoDataManager.EditingPlayerIndex >= 0)
			{
				NekoMekoDataManager.EditingPlayerIndex = -1;
				if (!string.IsNullOrEmpty(NekoMekoDataManager.CreatingPlayerModelKey))
					NekoMekoDataManager.CreatingPlayerModelKey = null;
				if (!string.IsNullOrEmpty(NekoMekoDataManager.CreatingPlayerSkinKey))
					NekoMekoDataManager.CreatingPlayerSkinKey = null;
			}
		}
		void Initialize()
		{
			LoadResModelAndSkin(ValuesDictionary);
			if (ResModel == null)
			{
				if (!string.IsNullOrEmpty(NekoMekoDataManager.CreatingPlayerModelKey))
				{//存在创建时的修改，将其应用
					SetResModel(NekoMekoDataManager.CreatingPlayerModelKey);
					NekoMekoDataManager.CreatingPlayerModelKey = null;
				}
				else
				{//无数据，采用默认
					string initialModelKey = ComponentPlayer.PlayerData.PlayerClass == PlayerClass.Male ? NekoMekoDataManager.DefaultMaleModelKey : NekoMekoDataManager.DefaultFemaleModelKey;
					SetResModel(initialModelKey);
				}
			}
			if (ResSkin == null)
			{
				if (!string.IsNullOrEmpty(NekoMekoDataManager.CreatingPlayerSkinKey))
				{//存在创建时的修改，将其应用
					SetResSkin(NekoMekoDataManager.CreatingPlayerSkinKey);
					NekoMekoDataManager.CreatingPlayerSkinKey = null;
				}
				else
				{//无数据，采用默认
					string key = NekoMekoDataManager.GetSkinKeyByCharacterSkinName(ComponentPlayer.PlayerData.CharacterSkinName);
					if (string.IsNullOrEmpty(key))
						key = ComponentPlayer.PlayerData.PlayerClass == PlayerClass.Male ? "Skin-Walter-ModelKey-ScMale" : "Skin-Doris-ModelKey-ScFemale";
					SetResSkin(key);
				}
			}
			m_initialized = true;
		}
		void SetBoneTransform(int boneIndex, Matrix matrix)
		{
			TargetComponent.SetBoneTransform(boneIndex, matrix);
			var bone = Model.Bones[boneIndex];
			BoneTransforms[bone.Name] = matrix;
		}
		Vector2 m_headAngles, m_handAngles1, m_handAngles2, m_legAngles1, m_legAngles2;
		readonly Dictionary<int, Matrix?> m_boneTransformsVanilla = [];
		void AnimateCreatureVanilla()
		{
			if (TargetComponent is not ComponentHumanModel componentHumanModel)
				return;
			Vector3 position = ComponentBody.Position;
			Vector3 vector = ComponentBody.Rotation.ToYawPitchRoll();
			if (componentHumanModel.m_lieDownFactorModel == 0f)
			{
				ComponentMount componentMount = componentHumanModel.m_componentRider?.Mount;
				float num = MathF.Sin((float)Math.PI * 2f * componentHumanModel.MovementAnimationPhase);
				position.Y += componentHumanModel.Bob;
				vector.X += componentHumanModel.m_headingOffset;
				float num2 = (float)MathUtils.Remainder((0.75 * NeorxnaResources.SubsystemGameInfo.TotalElapsedGameTime) + (GetHashCode() & 0xFFFF), 10000.0);
				float x = Math.Clamp(MathUtils.Lerp(-0.3f, 0.3f, SimplexNoise.Noise((1.02f * num2) - 100f)) + ComponentLocomotion.LookAngles.X + (1f * ComponentLocomotion.LastTurnOrder.X) + componentHumanModel.m_headingOffset, 0f - MathUtils.DegToRad(80f), MathUtils.DegToRad(80f));
				float y = Math.Clamp(MathUtils.Lerp(-0.3f, 0.3f, SimplexNoise.Noise((0.96f * num2) - 200f)) + ComponentLocomotion.LookAngles.Y, 0f - MathUtils.DegToRad(45f), MathUtils.DegToRad(45f));
				float num3 = 0f;
				float y2 = 0f;
				float x2 = 0f;
				float y3 = 0f;
				float num4 = 0f;
				float num5 = 0f;
				float num6 = 0f;
				float num7 = 0f;
				if (componentMount != null)
				{
					if (componentMount.Entity.ValuesDictionary.DatabaseObject.Name == "Boat")
					{
						position.Y -= 0.2f;
						vector.X += (float)Math.PI;
						num4 = 0.4f;
						num6 = 0.4f;
						num5 = 0.2f;
						num7 = -0.2f;
						num3 = 1.1f;
						x2 = 1.1f;
						y2 = 0.2f;
						y3 = -0.2f;
					}
					else
					{
						num4 = 0.5f;
						num6 = 0.5f;
						num5 = 0.15f;
						num7 = -0.15f;
						y2 = 0.55f;
						y3 = -0.55f;
					}
				}
				else if (ComponentLocomotion.IsCreativeFlyEnabled)
				{
					float num8 = ComponentLocomotion.LastWalkOrder.HasValue ? MathUtils.Min(0.03f * ComponentBody.Velocity.XZ.LengthSquared(), 0.5f) : 0f;
					num3 = -0.1f - num8;
					x2 = num3;
					y2 = MathUtils.Lerp(0f, 0.25f, SimplexNoise.Noise((1.07f * num2) + 400f));
					y3 = 0f - MathUtils.Lerp(0f, 0.25f, SimplexNoise.Noise((0.93f * num2) + 500f));
				}
				else if (componentHumanModel.MovementAnimationPhase != 0f)
				{
					num4 = -0.5f * num;
					num6 = 0.5f * num;
					num3 = componentHumanModel.m_walkLegsAngle * num;
					x2 = 0f - num3;
				}
				float num9 = 0f;
				if (ComponentMiner != null)
				{
					float num10 = MathF.Sin(MathF.Sqrt(ComponentMiner.PokingPhase) * (float)Math.PI);
					num9 = (ComponentMiner.ActiveBlockValue == 0) ? (1f * num10) : (0.3f + (1f * num10));
				}
				float num11 = (componentHumanModel.m_punchPhase != 0f) ? ((0f - MathUtils.DegToRad(90f)) * MathF.Sin((float)Math.PI * 2f * MathUtils.Sigmoid(componentHumanModel.m_punchPhase, 4f))) : 0f;
				float num12 = ((componentHumanModel.m_punchCounter & 1) == 0) ? num11 : 0f;
				float num13 = ((componentHumanModel.m_punchCounter & 1) != 0) ? num11 : 0f;
				float num14 = 0f;
				float num15 = 0f;
				float num16 = 0f;
				float num17 = 0f;
				if (componentHumanModel.m_rowLeft || componentHumanModel.m_rowRight)
				{
					float num18 = 0.6f * (float)Math.Sin(6.91150426864624 * NeorxnaResources.SubsystemTime.GameTime);
					float num19 = 0.2f + (0.2f * (float)Math.Cos(6.91150426864624 * (NeorxnaResources.SubsystemTime.GameTime + 0.5)));
					if (componentHumanModel.m_rowLeft)
					{
						num14 = num18;
						num15 = num19;
					}
					if (componentHumanModel.m_rowRight)
					{
						num16 = num18;
						num17 = 0f - num19;
					}
				}
				float num20 = 0f;
				float num21 = 0f;
				float num22 = 0f;
				float num23 = 0f;
				if (componentHumanModel.m_aimHandAngle != 0f)
				{
					num20 = 1.5f;
					num21 = -0.7f;
					num22 = componentHumanModel.m_aimHandAngle * 1f;
					num23 = 0f;
				}
				float num24 = (!ComponentLocomotion.IsCreativeFlyEnabled) ? 1 : 4;
				num4 += MathUtils.Lerp(-0.1f, 0.1f, SimplexNoise.Noise(num2)) + num12 + num14 + num20;
				num5 += MathUtils.Lerp(0f, num24 * 0.15f, SimplexNoise.Noise((1.1f * num2) + 100f)) + num15 + num21;
				num6 += num9 + MathUtils.Lerp(-0.1f, 0.1f, SimplexNoise.Noise((0.9f * num2) + 200f)) + num13 + num16 + num22;
				num7 += 0f - MathUtils.Lerp(0f, num24 * 0.15f, SimplexNoise.Noise((1.05f * num2) + 300f)) + num17 + num23;
				float s = MathUtils.Min(12f * NeorxnaResources.SubsystemTime.GameTimeDelta, 1f);
				m_headAngles += s * (new Vector2(x, y) - m_headAngles);
				m_handAngles1 += s * (new Vector2(num4, num5) - m_handAngles1);
				m_handAngles2 += s * (new Vector2(num6, num7) - m_handAngles2);
				m_legAngles1 += s * (new Vector2(num3, y2) - m_legAngles1);
				m_legAngles2 += s * (new Vector2(x2, y3) - m_legAngles2);
				if (ComponentBody.CrouchFactor == 1)
				{
					m_legAngles1 *= 0.5f;
					m_legAngles2 *= 0.5f;
				}
				float f = MathUtils.Sigmoid(ComponentBody.CrouchFactor, 4f);
				Vector3 position3 = new(position.X, position.Y - MathUtils.Lerp(0f, 0.7f, f), position.Z);
				Vector3 position4 = new(0f, MathUtils.Lerp(0f, 0.16f, f), MathUtils.Lerp(0f, 0.68f, f));
				Vector3 scale = new(1f, 1f, MathUtils.Lerp(1f, 0.5f, f));
				SetBoneTransformVanilla("Body", Matrix.CreateRotationY(vector.X) * Matrix.CreateTranslation(position3));
				SetBoneTransformVanilla("Head", Matrix.CreateRotationX(m_headAngles.Y) * Matrix.CreateRotationZ(0f - m_headAngles.X));
				SetBoneTransformVanilla("Arm1", Matrix.CreateRotationY(m_handAngles1.Y) * Matrix.CreateRotationX(m_handAngles1.X));
				SetBoneTransformVanilla("Arm2", Matrix.CreateRotationY(m_handAngles2.Y) * Matrix.CreateRotationX(m_handAngles2.X));
				SetBoneTransformVanilla("Leg1", Matrix.CreateRotationY(m_legAngles1.Y) * Matrix.CreateRotationX(m_legAngles1.X) * Matrix.CreateTranslation(position4) * Matrix.CreateScale(scale));
				SetBoneTransformVanilla("Leg2", Matrix.CreateRotationY(m_legAngles2.Y) * Matrix.CreateRotationX(m_legAngles2.X) * Matrix.CreateTranslation(position4) * Matrix.CreateScale(scale));
			}
			else
			{
				float num25 = MathUtils.Max(componentHumanModel.DeathPhase, componentHumanModel.m_lieDownFactorModel);
				float num26 = 1f - num25;
				Vector3 position2 = position + (num25 * 0.5f * ComponentBody.BoxSize.Y * Vector3.Normalize(ComponentBody.Matrix.Forward * new Vector3(1f, 0f, 1f))) + (num25 * Vector3.UnitY * ComponentBody.BoxSize.Z * 0.1f);
				SetBoneTransformVanilla("Body", Matrix.CreateFromYawPitchRoll(vector.X, (float)Math.PI / 2f * num25, 0f) * Matrix.CreateTranslation(position2));
				SetBoneTransformVanilla("Head", Matrix.Identity);
				SetBoneTransformVanilla("Arm1", Matrix.CreateRotationY(m_handAngles1.Y * num26) * Matrix.CreateRotationX(m_handAngles1.X * num26));
				SetBoneTransformVanilla("Arm2", Matrix.CreateRotationY(m_handAngles2.Y * num26) * Matrix.CreateRotationX(m_handAngles2.X * num26));
				SetBoneTransformVanilla("Leg1", Matrix.CreateRotationY(m_legAngles1.Y * num26) * Matrix.CreateRotationX(m_legAngles1.X * num26));
				SetBoneTransformVanilla("Leg2", Matrix.CreateRotationY(m_legAngles2.Y * num26) * Matrix.CreateRotationX(m_legAngles2.X * num26));
			}
		}
		Matrix? GetBoneTransformAnimator(int boneIndex) => GetBoneTransformAnimator(Model.Bones[boneIndex].Name);
		Matrix? GetBoneTransformAnimator(string boneName) => ComponentNeoModel.Animator.GetBoneTransform(boneName);
		void SetBoneTransformVanilla(string boneName, Matrix? transformation)
		{
			int boneIndex = Model.FindBone(boneName, false)?.Index ?? -1;
			if (boneIndex >= 0)
				SetBoneTransformVanilla(boneIndex, transformation);
		}
		void SetBoneTransformVanilla(int boneIndex, Matrix? transformation)
		{
			if (!m_boneTransformsVanilla.TryAdd(boneIndex, transformation))
				m_boneTransformsVanilla[boneIndex] = transformation;
		}
		Matrix? GetBoneTransformVanilla(int boneIndex)
		{
			if (m_boneTransformsVanilla.TryGetValue(boneIndex, out var transformation))
				return transformation;
			return null;
		}
		Matrix? RootTransformVanilla => GetBoneTransformVanilla(Model.RootBone.Index);

		//模型和皮肤配置
		public NekoResModel ResModel
		{
			get; private set;
		}
		public NekoResSkin ResSkin
		{
			get; private set;
		}

		public string ModelKey => ResModel?.Key ?? string.Empty;
		public string SkinKey => ResSkin?.Key ?? string.Empty;

		public bool SetResModel(string key)
		{
			if (string.IsNullOrEmpty(key))
				return false;
			var data = NekoMekoDataManager.FindModelData(key);
			if (data != null)
			{
				ResModel = data;
				SetModel(null);
				ComponentNekoMekoOuterModel?.SetModel(null);
				if (ComponentPlayer != null)
					SubsystemNekoPlayerData?.SetData(ComponentPlayer.PlayerData?.PlayerIndex ?? -1, data.Key, null);
				return true;
			}
			return false;
		}
		public bool SetResSkin(string key)
		{
			if (string.IsNullOrEmpty(key))
				return false;
			var data = NekoMekoDataManager.FindSkinData(key);
			if (data != null)
			{
				ResSkin = data;
				ComponentNeoModel.RenderMode = data.RenderMode;
				if (ResSkin.ResPath?.TryGetValue("TextureName", out var textureName) ?? false && !string.IsNullOrEmpty(textureName))
				{
					ComponentNeoModel.SetBasicTexture(ResSkin.GetRes(textureName) as Texture2D);
				}
				else
					textureName = string.Empty;
				if (ResSkin.ResPath?.TryGetValue("PBRMapName", out var pbrMapName) ?? false && !string.IsNullOrEmpty(pbrMapName))
				{
					ComponentNeoModel.PBRMap = ResSkin.GetRes(pbrMapName) as Texture2D;
				}
				if (ResSkin.ResPath?.TryGetValue("NormalMapName", out var normalMapName) ?? false && !string.IsNullOrEmpty(normalMapName))
				{
					ComponentNeoModel.NormalMap = ResSkin.GetRes(normalMapName) as Texture2D;
				}
				if (ResModel?.AllowClotheOverride ?? false)
				{
					ComponentPlayer?.PlayerData?.CharacterSkinName = NekoMekoDataManager.GetCharacterSkinNameByTextureName(textureName);
					ComponentNeoModel.ClothingOverride = true;
					//var name = NekoMekoDataManager.GetCharacterSkinNameByTextureName(textureName);
					//Debug.LogDebug(name);
				}
				else
					ComponentNeoModel.ClothingOverride = false;
				if (ComponentPlayer != null)
					SubsystemNekoPlayerData?.SetData(ComponentPlayer.PlayerData?.PlayerIndex ?? -1, null, data.Key);
				return true;
			}
			return false;
		}

		public void LoadResModelAndSkin(ValuesDictionary valuesDictionary)
		{
			string modelKey = valuesDictionary.GetValue("ModelKey", string.Empty);
			string skinKey = valuesDictionary.GetValue("SkinKey", string.Empty);
			if (ComponentPlayer != null)
			{
				SubsystemNekoPlayerData.GetData(ComponentPlayer.PlayerData.PlayerIndex, out string modelKey2, out string skinKey2);
				if (string.IsNullOrEmpty(modelKey))
					modelKey = modelKey2;
				if (string.IsNullOrEmpty(skinKey))
					skinKey = skinKey2;
			}
			SetResModel(modelKey);
			SetResSkin(skinKey);
		}

		public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
		{
			base.Save(valuesDictionary, entityToIdMap);
			valuesDictionary.SetValue("ModelKey", ModelKey);
			valuesDictionary.SetValue("SkinKey", SkinKey);
		}

	}
}
